package com.nhncorp.neptune.common;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Latch {
  ReentrantLock latchLock = new ReentrantLock();
  boolean isBlocked = false;
  int numOfThread;
  Condition emptyCondition;
  Condition blockCondition;
			    
  public Latch() {
    emptyCondition = latchLock.newCondition();
    blockCondition = latchLock.newCondition();
  }

  public void enter() throws InterruptedException {
    latchLock.lockInterruptibly();
    try {
      while(isBlocked) {
        blockCondition.await();
      }

      numOfThread++;
    } finally {
      latchLock.unlock();
    }
  }

  public void exit() {
    latchLock.lock();
    try {
      if (--numOfThread == 0 && isBlocked) {
        emptyCondition.signalAll();
      }      
    } finally {
      latchLock.unlock();
    }
  }

  public void block() throws InterruptedException {
    latchLock.lockInterruptibly();
    try {
      isBlocked = true;
      while(numOfThread > 0) {
        emptyCondition.await();
      }
    } finally {
      latchLock.unlock();
    }
  }


  public void unblock() {
    latchLock.lock();
    try {
      isBlocked = false;
      blockCondition.signalAll();
    } finally {
      latchLock.unlock();
    }
  }
}

